package controller;

import drawing.DrawAbles;
import model.ModelContext;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;

import java.util.Collection;
import java.util.LinkedList;


public class GameController implements Runnable{
	private final ModelContext modelcontext;
	private final Collection<Executable> controllers = new LinkedList<Executable>();
	private final Collection<Executable> newcontrollers = new LinkedList<Executable>();
	private final Collection<Executable> remcontrollers = new LinkedList<Executable>();
	private DrawAbles drawing = new DrawAbles();
	
	
	/** the number of maximum frames rendered per second */
	private static final int FPS = 30;
	
	/** boolean to stop the thread */
	private boolean stop = false;
	
	public GameController(ModelContext mc){
		this.modelcontext=mc;
	}
	
	public GameController(ModelContext mc,Collection<Executable> controllers){
		this.controllers.addAll(controllers);
		this.modelcontext = mc;
	}
	
	public GameController(ModelContext mc,Collection<Executable> controllers, DrawAbles customdrawer){
		this.controllers.addAll(controllers);
		this.modelcontext = mc;
		this.drawing = customdrawer;
	}
	
	public GameController(ModelContext mc,DrawAbles customdrawing){
		this.modelcontext=mc;
		this.drawing=customdrawing;
	}

	@Override
	public void run() {
		try {
			Display.create();
		} catch (LWJGLException e) {
			System.out.println("Failed to create the display.");
			e.printStackTrace();
		}
		SystemContext syscon = new SystemContext(this);
		while(!stop){
			//add/destroy the new controllers
			for(Executable e:newcontrollers){
				controllers.add(e);
			}
			newcontrollers.clear();
			for(Executable e:remcontrollers){
				controllers.remove(e);
			}
			remcontrollers.clear();
			
			//do one step in the model
			//update the model (create/destroy objects)
			modelcontext.update();
			for(Executable m:controllers){
				m.doStep(modelcontext,syscon);
			}
			
			//update the model
			modelcontext.update();
			//draw the model
			drawing.draw();
			
			//update the screen and key/mouse IO
			Display.update();
			//adhere to the fps
			Display.sync(FPS);
		}
		//remove the display when the game ends
		Display.destroy();
	}
	
	public void addController(Executable exec){
		newcontrollers.add(exec);
	}
	
	public void removeController(Executable exec){
		remcontrollers.add(exec);
	}
	
	public void stop(){
		stop = true;
	}
	
	@Override
	public void finalize()throws Throwable{
		if(!stop){
			Display.destroy();
		}
        super.finalize();
	}
}
